package com.example.redisson.config;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Objects;

@Slf4j
@Configuration
public class RedissonConfig {

    private static final String PREFIX = "redis://";

    @Resource
    private RedisProperties redisProperties;

    /**
     * 配置 Redis 客户端 RedissonClient
     */
    // 既然使用了 Redisson 客户端，那么在使用 Redis 操作数据的时候，用 RedissonClient 替代 RedisTemplate 即可。
    // Redisson 是一个高性能的 Java 客户端，用于与 Redis 服务器交互。它不仅提供了一个简单的 Redis 客户端接口，
    // 而且还提供了一系列高级功能，使开发人员能够轻松地构建分布式应用程序。
    @Bean(destroyMethod = "shutdown")
    public RedissonClient initRedissonClient() {
        RedisProperties.Sentinel sentinel = redisProperties.getSentinel();
        if (Objects.nonNull(sentinel)) {
            log.info("检测到配置了哨兵模式，redisson 客户端将采用哨兵模式");
            return redissonSentinel();
        }

        RedisProperties.Cluster cluster = redisProperties.getCluster();
        if (Objects.nonNull(cluster)) {
            log.info("检测到配置了集群模式，redisson 客户端将采用集群模式");
            return redissonCluster();
        }

        log.info("没有检测到哨兵或集群配置，redisson 客户端将采用单机模式");
        return redissonSingle();
    }

    /**
     * https://github.com/redisson/redisson/tree/master/redisson-spring-boot-starter
     * 哨兵模式，配置参考 https://github.com/redisson/redisson/wiki/2.-Configuration#27-sentinel-mode
     */
    private RedissonClient redissonSentinel() {
        // Redis 主节点的名称是哨兵进程中用来监测主从服务切换情况的
        String masterName = redisProperties.getSentinel().getMaster();
        // 哨兵节点的地址
        // 可以尝试直接为 node 节点地址配置为 redis://host:port
        String[] nodes = redisProperties.getSentinel().getNodes()
                .stream()
                .map(node -> PREFIX + node)
                .toArray(String[]::new);

        System.out.println("哨兵节点的地址：" + Arrays.toString(nodes));
        // 用于节点身份验证的密码
        String password = redisProperties.getPassword();
        Config config = new Config();
        SentinelServersConfig sentinelServersConfig = config.useSentinelServers();
        // 判断密码
        if (StringUtils.hasText(password)) {
            sentinelServersConfig.setPassword(password);
        }
        sentinelServersConfig.setConnectTimeout(5000);
        sentinelServersConfig.setCheckSentinelsList(false);
        // 设置 Redis 主节点的名称
        sentinelServersConfig.setMasterName(masterName);
        // 哨兵节点的地址，格式为：redis://host:port
        sentinelServersConfig.addSentinelAddress(nodes);
        return Redisson.create(config);
    }

    /**
     * 集群模式，配置参考 https://github.com/redisson/redisson/wiki/2.-Configuration#24-cluster-mode
     */
    private RedissonClient redissonCluster() {
        String[] nodes = redisProperties.getCluster().getNodes().toArray(String[]::new);
        String password = redisProperties.getPassword();
        // 声明一个配置类
        Config config = new Config();
        ClusterServersConfig clusterServersConfig = config.useClusterServers();
        // 判断密码
        if (StringUtils.hasText(password)) {
            clusterServersConfig.setPassword(password);
        }
        clusterServersConfig.addNodeAddress(nodes);
        return Redisson.create(config);
    }

    /**
     * 单机模式，配置参考 https://github.com/redisson/redisson/wiki/2.-Configuration#26-single-instance-mode
     */
    private RedissonClient redissonSingle() {
        Config config = new Config();
        SingleServerConfig serverConfig = config.useSingleServer();

        String password = redisProperties.getPassword();
        String url = redisProperties.getUrl();
        if (StringUtils.hasText(url)) {
            serverConfig.setAddress(url);
            if (StringUtils.hasText(password)) {
                serverConfig.setPassword(password);
            }
            return Redisson.create(config);
        }

        log.warn("检测到你还没有配置 Redis 相关信息，请检查 application.yaml 文件");
        serverConfig.setAddress("redis://localhost:6379");
        if (StringUtils.hasText(password)) {
            serverConfig.setPassword(password);
        }
        return Redisson.create(config);
    }

}

// redisson-spring-boot-starter 官方文档  https://github.com/redisson/redisson/tree/master/redisson-spring-boot-starter#2-add-settings-into-applicationsettings-file
// Redisson 配置参考 https://github.com/redisson/redisson/wiki/2.-Configuration
// Redisson 使用手册 https://www.bookstack.cn/read/redisson-wiki-zh/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95.md